// 《围棋》作者版权所有。保留所有权利。
// 此源代码的使用受BSD样式
// 许可证的约束，该许可证可以在许可证文件中找到。

package fuzz

import (
	"math/bits"
	"os"
	"strconv"
	"strings"
	"sync/atomic"
	"time"
)

type mutatorRand interface {
	uint32() uint32
	intn(int) int
	uint32n(uint32) uint32
	exp2() int
	bool() bool

	save(randState, randInc *uint64)
	restore(randState, randInc uint64)
}

// pcg中的函数实现了一个32位的带64位周期的PRNG:pcg xsh rr 
// 64 32。看见https:
// 实现专门针对模糊化的需求：简单的
// 创建和使用，没有可复制性，没有并发安全性，只有
// 必要的方法，针对速度进行了优化。

var globalInc uint64 // PCG流

const multiplier uint64 = 6364136223846793005

// pcgRand是一个PRNG。它不应该被复制或共享。没有Rand方法是
// 并发安全的。
type pcgRand struct {
	noCopy noCopy // 帮助避免错误：请兽医确保我们不会复制
	state  uint64
	inc    uint64
}

func godebugSeed() *int {
	debug := strings.Split(os.Getenv("GODEBUG"), ",")
	for _, f := range debug {
		if strings.HasPrefix(f, "fuzzseed=") {
			seed, err := strconv.Atoi(strings.TrimPrefix(f, "fuzzseed="))
			if err != nil {
				panic("malformed fuzzseed")
			}
			return &seed
		}
	}
	return nil
}

// newPcgRand生成一个新的种子Rand，可供使用。
func newPcgRand() *pcgRand {
	r := new(pcgRand)
	now := uint64(time.Now().UnixNano())
	if seed := godebugSeed(); seed != nil {
		now = uint64(*seed)
	}
	inc := atomic.AddUint64(&globalInc, 1)
	r.state = now
	r.inc = (inc << 1) | 1
	r.step()
	r.state += now
	r.step()
	return r
}

func (r *pcgRand) step() {
	r.state *= multiplier
	r.state += r.inc
}

func (r *pcgRand) save(randState, randInc *uint64) {
	*randState = r.state
	*randInc = r.inc
}

func (r *pcgRand) restore(randState, randInc uint64) {
	r.state = randState
	r.inc = randInc
}

// uint32返回伪随机uint32。
func (r *pcgRand) uint32() uint32 {
	x := r.state
	r.step()
	return bits.RotateLeft32(uint32(((x>>18)^x)>>27), -int(x>>59))
}

// intn在[0，n]中返回一个伪随机数。
// n必须适合uint32。
func (r *pcgRand) intn(n int) int {
	if int(uint32(n)) != n {
		panic("large Intn")
	}
	return int(r.uint32n(uint32(n)))
}

// uint32n在[0，n]中返回一个伪随机数。
// 
// 有关实现细节，请参阅：
// https:
// https:
func (r *pcgRand) uint32n(n uint32) uint32 {
	v := r.uint32()
	prod := uint64(v) * uint64(n)
	low := uint32(prod)
	if low < n {
		thresh := uint32(-int32(n)) % n
		for low < thresh {
			v = r.uint32()
			prod = uint64(v) * uint64(n)
			low = uint32(prod)
		}
	}
	return uint32(prod >> 32)
}

// exp2以1/2^（n+1）的概率生成n。
func (r *pcgRand) exp2() int {
	return bits.TrailingZeros32(r.uint32())
}

// bool生成一个随机bool。
func (r *pcgRand) bool() bool {
	return r.uint32()&1 == 0
}

// 第一次使用后，禁止复制的结构中可能会嵌入任何副本。
// 参见https:
// 详细信息。
type noCopy struct{}

// lock是“go vet”中的-copylocks检查器使用的一种无操作。
func (*noCopy) lock()   {}
func (*noCopy) unlock() {}
